/**********************************************
 * Cours :			 LOG120
 * Session :		 Automne 2011
 * Groupe : 		 03
 * Projet : 		 Lab 1
 * Étudiant(e)(s) : Garcia Carrasco, Maria
 * 					 Bolduc, Andrew
 * Code(s) perm. :   GARM05559006
 * 					 BOLA03098701
 * Professeur : 	 Yannick Boucher
 * Chargé de labo:  Jonathan Simard
 * Nom du fichier :  ShapeNodeList.java
 * Date crée :      2011-10-11
 **********************************************
 * Historique des modifications
 **********************************************
 * 2011-10-11		Version initiale Andrew Bolduc
 * 2011-10-22		Modifiée par Maria Garcia Carrasco
 **********************************************
 *
 *
 *
 * @author Maria Garcia Carrasco et Andrew Bolduc
 * Cette classe gère toutes les formes fournies par le serveur
 * de forme.
 */

package nodes;

import interfaces.IShape;
import shapes.AbstractShape;
import shapes.ShapeSettings;

public class ShapeNodeList implements Cloneable {
	
	private final int MAX_NUMBER_OF_SHAPES;
	private ShapeNode originalFirst;
	private ShapeNode originalLast;
	
	public ShapeNodeList(int MAX_NUMBER_OF_SHAPES) {
		originalFirst = null;
		originalLast = null;
		this.MAX_NUMBER_OF_SHAPES = MAX_NUMBER_OF_SHAPES;
	}
	
	public boolean isEmpty() {
		return originalFirst == null;
	}
	
	public int getSize() {
		int count = 0;
		ShapeNode tempNode = originalFirst;
		while(tempNode != null) {
			count++;
			tempNode = tempNode.getNext();
		}
		return count;
	}
	
	public boolean add(AbstractShape shape) {
		if(isEmpty()) {
			originalLast = new ShapeNode(shape);
			originalFirst = originalLast;
			return true;
		}
		else {
			originalLast.setNext(new ShapeNode(shape, null, originalLast));
			originalLast = originalLast.getNext();
			removeExtra();
			return true;
		}
	}
	
	public boolean addAt(AbstractShape shape, int index) {
		if(index < 0 || index > getSize() || index >= MAX_NUMBER_OF_SHAPES) {
			return false;
		}
		
		if(index == 0) {
			ShapeNode tempNode = originalFirst;
			originalFirst = new ShapeNode(shape, tempNode, null);
			if(tempNode != null) {
				tempNode.setPrevious(originalFirst);
			}
			if(originalLast == null) {
				originalLast = originalFirst;
			}
			removeExtra();
			return true;
		}
		
		ShapeNode predecessor = originalFirst;
		for(int i = 1; i <= (index - 1); i++) {
			predecessor = predecessor.getNext();
		}
		
		ShapeNode successor = predecessor.getNext();
		ShapeNode middle = new ShapeNode(shape, successor, predecessor);
		predecessor.setNext(middle);
		if(successor == null) {
			originalLast = middle;
		}
		else {
			successor.setPrevious(middle);
		}
		removeExtra();
		
		return true;
	}
	
	private void removeExtra() {
		if(getSize() > MAX_NUMBER_OF_SHAPES) {
			//originalFirst = originalFirst.getNext();
			originalLast = originalLast.getPrevious();
			originalLast.setNext(null);
		}
	}
	
	public boolean remove(int shapeID) {
		if(isEmpty()) {
			return false;
		}
		
		ShapeNode target = originalFirst;
		while(target != null && !(shapeID == target.getData().getShapeID())) {
			target = target.getNext();
		}
		
		if(target == null) {
			return false;
		}
		
		ShapeNode predecessor = target.getPrevious();
		ShapeNode successor = target.getNext();
		
		if(predecessor == null) {
			originalFirst = successor;
		}
		else {
			predecessor.setNext(successor);
		}
		
		if(successor == null) {
			originalLast = predecessor;
		}
		else {
			successor.setPrevious(predecessor);
		}
		
		return true;
	}
	
	public boolean removeAt(int index) {
		if(index < 0 || index >= getSize() || index > MAX_NUMBER_OF_SHAPES || isEmpty()) {
			return false;
		}
		
		ShapeNode target = originalFirst;
		for(int i = 1; i <= index; i++) {
			target = target.getNext();
		}
		
		ShapeNode predecessor = target.getPrevious();
		ShapeNode successor = target.getNext();
		
		if(predecessor == null) {
			originalFirst = successor;
		}
		else {
			predecessor.setNext(successor);
		}
		
		if(successor == null) {
			originalLast = predecessor;
		}
		else {
			successor.setPrevious(predecessor);
		}
		
		return true;
	}
	
	public int getIndex(ShapeNode shapeNode) {
		ShapeNode target = originalFirst;
		for(int i = 0; i < getSize(); i++) {
			if(shapeNode.getData().getShapeID() == target.getData().getShapeID()) {
				return i;
			}
		}
		return -1;
	}
	
	/*public void swapNodes(ShapeNode node1, ShapeNode node2){
		ShapeNode tempNode1 = node1;
		ShapeNode tempNode2 = node2;
		
		node1 = node2;*/
		/**node1.setNext(node2.getNext());
		node1.setPrevious(node2.getPrevious());
		**/
		/*node2 = tempNode1;
	}*/
	
	public ShapeNodeIterator createIteratorFromFirst() {
		/*sortedFirst = originalFirst;
		return new ShapeNodeIterator(sortedFirst);*/
		return new ShapeNodeIterator(originalFirst);
	}
	
	public ShapeNodeIterator createIteratorFromLast() {
		/*sortedLast = originalLast;
		return new ShapeNodeIterator(sortedLast);*/
		return new ShapeNodeIterator(originalLast);
	}
	
	public ShapeNode getFirstNode() {
		return originalFirst;
	}
	
	public ShapeNode getLastNode() {
		return originalLast;
	}
	
	public void swap(ShapeNode first, ShapeNode second) {
		IShape shape = first.getData();
		first.setData(second.getData());
		second.setData(shape);
	}
    
	@TODO 
	/**the error is here since you didnt initiate iterator.**/
    public void setOriginal() throws CloneNotSupportedException {
        ShapeNodeIterator iterator = createIteratorFromFirst();
        while(!iterator.isNull()) {
            ShapeNode shapeNode = iterator.next();
            shapeNode.setData(((ShapeNode)shapeNode.clone()).getOriginal());
        }
    }
	
	public void showNewOrder() {
		ShapeNodeIterator iterator = createIteratorFromFirst();
		int xCoord = 0;
		int yCoord = 0;
		while(!iterator.isNull()) {
            ShapeNode shapeNode = iterator.next();
            if(shapeNode.getData().getShapeName().equalsIgnoreCase(ShapeSettings.getRectangleName()) || shapeNode.getData().getShapeName().equalsIgnoreCase(ShapeSettings.getSquareName())) {
            	shapeNode.getData().setSecondX(Math.abs(shapeNode.getData().getSecondX() - (shapeNode.getData().getxCoord() - xCoord)));
                shapeNode.getData().setSecondY(Math.abs(shapeNode.getData().getSecondY() - (shapeNode.getData().getyCoord() - yCoord)));
                shapeNode.getData().setxOrigin(xCoord);
                shapeNode.getData().setyOrigin(yCoord);
            }
            else if(shapeNode.getData().getShapeName().equalsIgnoreCase(ShapeSettings.getOvalName()) || shapeNode.getData().getShapeName().equalsIgnoreCase(ShapeSettings.getCircleName())) {
            	shapeNode.getData().setxOrigin(xCoord);
                shapeNode.getData().setyOrigin(yCoord);
            }
            xCoord += 40;
            yCoord += 40;
        }
	}

}